package net.shopxx.boot;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.converter.BufferedImageHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mobile.device.DeviceWebArgumentResolver;
import org.springframework.mobile.device.site.SitePreferenceWebArgumentResolver;
import org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver;
import org.springframework.stereotype.Controller;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.WebContentInterceptor;
import org.springframework.web.servlet.mvc.method.annotation.ServletWebArgumentResolverAdapter;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

import net.shopxx.Setting.CaptchaType;
import net.shopxx.audit.AuditLogInterceptor;
import net.shopxx.audit.AuditLogMethodArgumentResolver;
import net.shopxx.captcha.CaptchaInterceptor;
import net.shopxx.interceptor.ListInterceptor;
import net.shopxx.security.CsrfInterceptor;
import net.shopxx.security.CurrentCartHandlerInterceptor;
import net.shopxx.security.CurrentCartMethodArgumentResolver;
import net.shopxx.security.CurrentUserHandlerInterceptor;
import net.shopxx.security.CurrentUserMethodArgumentResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"net.shopxx"},useDefaultFilters=false,includeFilters={@Filter(type=FilterType.ANNOTATION,value=Controller.class),@Filter(type=FilterType.ANNOTATION,value=ControllerAdvice.class)})
public class WebConfig extends WebMvcConfigurerAdapter {
    
    @Autowired
    private Environment env;
    
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        super.addArgumentResolvers(argumentResolvers);
        argumentResolvers.add(new ServletWebArgumentResolverAdapter(new DeviceWebArgumentResolver()));
        argumentResolvers.add(new ServletWebArgumentResolverAdapter(new SitePreferenceWebArgumentResolver()));
        argumentResolvers.add(currentUserMethodArgumentResolver());
        argumentResolvers.add(currentCartMethodArgumentResolver());
        argumentResolvers.add(new AuditLogMethodArgumentResolver());
    }
    
    @Bean
    public CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver(){
        return new CurrentUserMethodArgumentResolver();
    }
    @Bean
    public CurrentCartMethodArgumentResolver currentCartMethodArgumentResolver(){
        return new CurrentCartMethodArgumentResolver();
    }
    
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        supportedMediaTypes.add(MediaType.TEXT_HTML);
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
        converters.add(new BufferedImageHttpMessageConverter());
        converters.add(mappingJackson2HttpMessageConverter);
    }
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/favicon.ico").addResourceLocations("/favicon.ico").setCachePeriod(86400);
        registry.addResourceHandler("/robots.txt").addResourceLocations("/robots.txt").setCachePeriod(86400);
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/").setCachePeriod(86400);
        registry.addResourceHandler("/upload/**").addResourceLocations("/upload/").setCachePeriod(86400);
    }
    
    @Bean
    public CurrentUserHandlerInterceptor memberCurrentUserHandlerInterceptor(){
        return new CurrentUserHandlerInterceptor();
    }
    @Bean
    public CurrentUserHandlerInterceptor businessCurrentUserHandlerInterceptor(){
        return new CurrentUserHandlerInterceptor();
    };
    @Bean
    public CurrentUserHandlerInterceptor adminCurrentUserHandlerInterceptor(){
        return new CurrentUserHandlerInterceptor();
    };
    @Bean
    public CurrentCartHandlerInterceptor currentCartHandlerInterceptor(){
        return new CurrentCartHandlerInterceptor();
    };
    
    @Override
    public void addInterceptors(final InterceptorRegistry registry) {
        WebContentInterceptor cacheInterceptor = new WebContentInterceptor();
        cacheInterceptor.setCacheSeconds(86400);
        registry.addInterceptor(cacheInterceptor).addPathPatterns("/resources/**");
        
        WebContentInterceptor nocacheInterceptor = new WebContentInterceptor();
        nocacheInterceptor.setCacheSeconds(0);
        registry.addInterceptor(nocacheInterceptor).addPathPatterns("/cart/**","/order/**","/member/**","/admin/**");
        
        CurrentUserHandlerInterceptor memberCurrentUserHandlerInterceptor = memberCurrentUserHandlerInterceptor();
        memberCurrentUserHandlerInterceptor.setUserClass(net.shopxx.entity.Member.class);
        registry.addInterceptor(memberCurrentUserHandlerInterceptor).addPathPatterns("/cart/**","/order/**","/member/**");
        
        CurrentUserHandlerInterceptor adminCurrentUserHandlerInterceptor = adminCurrentUserHandlerInterceptor();
        adminCurrentUserHandlerInterceptor.setUserClass(net.shopxx.entity.Admin.class);
        registry.addInterceptor(adminCurrentUserHandlerInterceptor).addPathPatterns("/admin/**");
        
        CurrentCartHandlerInterceptor currentCartHandlerInterceptor = currentCartHandlerInterceptor();
        registry.addInterceptor(currentCartHandlerInterceptor).addPathPatterns("/cart/**","/order/**");
        
        CsrfInterceptor csrfInterceptor = new CsrfInterceptor();
        registry.addInterceptor(csrfInterceptor).addPathPatterns("/**").excludePathPatterns("/payment/**");
        
        CaptchaInterceptor memberRegisterCaptchainterceptor = memberRegisterCaptchainterceptor();
        memberRegisterCaptchainterceptor.setCaptchaType(CaptchaType.memberRegister);
        registry.addInterceptor(memberRegisterCaptchainterceptor).addPathPatterns("/member/register/submit");
        
        CaptchaInterceptor reviewCaptchainterceptor = reviewCaptchainterceptor();
        reviewCaptchainterceptor.setCaptchaType(CaptchaType.review);
        registry.addInterceptor(reviewCaptchainterceptor).addPathPatterns("/member/review/save");
        
        CaptchaInterceptor consultationCaptchainterceptor = consultationCaptchainterceptor();
        consultationCaptchainterceptor.setCaptchaType(CaptchaType.consultation);
        registry.addInterceptor(consultationCaptchainterceptor).addPathPatterns("/consultation/save");
        
        CaptchaInterceptor forgotPasswordCaptchainterceptor = forgotPasswordCaptchainterceptor();
        forgotPasswordCaptchainterceptor.setCaptchaType(CaptchaType.forgotPassword);
        registry.addInterceptor(forgotPasswordCaptchainterceptor).addPathPatterns("/password/forgot");
        
        CaptchaInterceptor resetPasswordCaptchainterceptor = resetPasswordCaptchainterceptor();
        resetPasswordCaptchainterceptor.setCaptchaType(CaptchaType.resetPassword);
        registry.addInterceptor(resetPasswordCaptchainterceptor).addPathPatterns("/password/reset");
        
        ListInterceptor listInterceptor = new ListInterceptor();
        registry.addInterceptor(listInterceptor).addPathPatterns("/admin/**");
        
        AuditLogInterceptor auditLogInterceptor = auditLogInterceptor();
        registry.addInterceptor(auditLogInterceptor).addPathPatterns("/admin/**");
        
        super.addInterceptors(registry);
    }
    
    @Bean
    public CaptchaInterceptor memberRegisterCaptchainterceptor(){
        return new CaptchaInterceptor();
    }
    
    @Bean
    public CaptchaInterceptor businessRegisterCaptchainterceptor(){
        return new CaptchaInterceptor();
    }
    
    @Bean
    public CaptchaInterceptor reviewCaptchainterceptor(){
        return new CaptchaInterceptor();
    }
    
    @Bean
    public CaptchaInterceptor consultationCaptchainterceptor(){
        return new CaptchaInterceptor();
    }
    
    @Bean
    public CaptchaInterceptor forgotPasswordCaptchainterceptor(){
        return new CaptchaInterceptor();
    }
    
    @Bean
    public CaptchaInterceptor resetPasswordCaptchainterceptor(){
        return new CaptchaInterceptor();
    }
    
    @Bean
    public AuditLogInterceptor auditLogInterceptor(){
        return new AuditLogInterceptor();
    }
    
    @Bean  
    public javax.validation.Validator validator(@Autowired MessageSource messageSource) {  
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();  
        localValidatorFactoryBean.setValidationMessageSource(messageSource);  
        return localValidatorFactoryBean;  
    } 
    
    @Bean
    public ViewResolver viewResolver(){
        FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver(); 
        freeMarkerViewResolver.setContentType(env.getProperty("html_content_type"));
        freeMarkerViewResolver.setSuffix(env.getProperty("suffix"));
        freeMarkerViewResolver.setRequestContextAttribute("requestContext");
        LiteDeviceDelegatingViewResolver liteDeviceDelegatingViewResolver = new LiteDeviceDelegatingViewResolver(freeMarkerViewResolver);
        liteDeviceDelegatingViewResolver.setMobilePrefix("mobile/");
        liteDeviceDelegatingViewResolver.setTabletPrefix("tablet/");
        liteDeviceDelegatingViewResolver.setEnableFallback(true);
        return liteDeviceDelegatingViewResolver;
    }
    
    @Bean
    public MultipartResolver  multipartResolver(){
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("UTF-8");
        return resolver;
    }   
}
